﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;
using System.Windows.Threading;
using System.Threading;
using System.IO;
using NetFlux;
using System.Net.NetworkInformation;
using MahApps.Metro;

namespace NetFlux4i
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow
    {
        Process OpenVPN;
        AppLimit.NetSparkle.Sparkle updater;
        private bool IsOpenVPNRunning
        {
            get
            {
                try
                {
                    return !OpenVPN.HasExited;
                }
                catch
                {
                    return false;
                }
            }
        }
        private string Username
        {
            get
            {
                return NetFlux4i.Properties.Settings.Default.Username;
            }
            set
            {
                NetFlux4i.Properties.Settings.Default.Username = value;
                NetFlux4i.Properties.Settings.Default.Save();
            }
        }
        private string Password
        {
            get
            {
                return NetFlux4i.Properties.Settings.Default.Password;
            }
            set
            {
                NetFlux4i.Properties.Settings.Default.Password = value;
                NetFlux4i.Properties.Settings.Default.Save();
            }
        }
        private int ServerId
        {
            get
            {
                return NetFlux4i.Properties.Settings.Default.Server;
            }
            set
            {
                NetFlux4i.Properties.Settings.Default.Server = value;
                NetFlux4i.Properties.Settings.Default.Save();
            }
        }
        private int NetworkId
        {
            get
            {
                return NetFlux4i.Properties.Settings.Default.Network;
            }
            set
            {
                NetFlux4i.Properties.Settings.Default.Network = value;
                NetFlux4i.Properties.Settings.Default.Save();
            }
        }
        private Server Server
        {
            get
            {
                return ServerList.Servers[ServerId];
            }
        }
        private SANetworks Network
        {
            get
            {
                return (SANetworks)(NetworkId);
            }
        }

        public MainWindow()
        {
            InitializeComponent();
        }

        const string SERVER_FILENAME = "servers.dat";
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {

            if (File.Exists(SERVER_FILENAME))
                ServerList.Import(SERVER_FILENAME);
            else
            {
                NetFlux.ServerList.Init();
            }

            listViewServer.Items.Clear();
            foreach (NetFlux.Server s in NetFlux.ServerList.Servers)
            {
                listViewServer.Items.Add(s);
            }

            //Kill OpenVPN
            foreach (Process proc in Process.GetProcessesByName("openvpn.exe"))
            {
                try
                {
                    proc.Kill();
                }
                catch { }
            }
            foreach (Process proc in Process.GetProcessesByName("openvpn"))
            {
               
                try
                {
                    proc.Kill();
                }
                catch { }
            }
            //load settings
            
            listViewServer.SelectedIndex = ServerId;
            txtBoxPassword.Password = Password;
            txtBoxUsername.Text = Username;

            for (int i = 0; i < listBoxNetwork.Items.Count;i++ )
            {
                if (int.Parse((listBoxNetwork.Items[i] as Image).Tag.ToString()) == NetworkId)
                {
                    listBoxNetwork.SelectedIndex = i;
                }
            }

            UpdateStatus();
        }

        string eventname = "";
        void StartOpenVPN()
        {
            const string accdatafile = "OpenVPN\\data.up";
            StreamWriter writer = new StreamWriter(accdatafile);
            writer.WriteLine(Username);
            writer.WriteLine(Password);
            writer.Close();
           //Start OpenVPN

            string configFile = System.IO.Path.GetFullPath("OpenVPN\\client.ovpn");

         /* //  if (App.Arguments_Used)
            {
                if (!string.IsNullOrEmpty(App.Options.VPNFile))
                {
                    configFile = App.Options.VPNFile;
                    if (App.Options.Verbose)
                        Console.WriteLine("Using custom OpenVPN config: " + configFile);
                }

            }*/
            eventname = "NetFlux4i_" + new Random().Next(1000);
            string args = "--config \"" + configFile + "\" --service {araar} 0";
            args=args.Replace("{araar}", eventname);
            ProcessStartInfo startInfo = new ProcessStartInfo("openvpn.exe", args);
            startInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(configFile);
          //  System.IO.File.WriteAllLines(startInfo.WorkingDirectory + "\\username.txt", new string[] { Username, Password });

            startInfo.UseShellExecute = false;
            startInfo.RedirectStandardOutput = true;
            startInfo.RedirectStandardInput = true;
            startInfo.CreateNoWindow = true;
            OpenVPN = Process.Start(startInfo);
            OpenVPN.EnableRaisingEvents = true;
            OpenVPN.Exited += new EventHandler(OpenVPN_Exited);

            System.IO.StreamReader reader = OpenVPN.StandardOutput;
            txtLogOut.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate
            {
                txtLogOut.Clear();
            }));
            new Thread(() =>
            {
                const int maxLines = 17;
                Queue<string> lines = new Queue<string>(maxLines);
                while (!reader.EndOfStream)
                {
                    string s = reader.ReadLine();

                    txtLogOut.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate
                    {
                        if (txtLogOut.LineCount > maxLines-1)
                            txtLogOut.Text = txtLogOut.Text.Remove(0, txtLogOut.Text.IndexOf("\r\n"));

                        lines.Enqueue(s);
                        if (lines.Count > maxLines)
                            lines.Dequeue();
                        txtLogOut.Clear();
                        foreach (string s1 in lines)
                            txtLogOut.Text += s1 + "\r\n";
                        txtLogOut.ScrollToEnd();
                        try
                        {
                           System.IO.File.AppendAllText("openvpn.txt", s + "\r\n");
                        }
                        catch
                        {
                        }
                    }));

                }
                txtLogOut.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate
                {
                    
                    txtLogOut.ScrollToEnd();
                }));

            }) { IsBackground = true }.Start();

            new Thread(() =>
                {
                    Thread.Sleep(1000);
                    try
                    {
                        File.Delete(accdatafile);
                    }
                    catch
                    {
                    }

                }).Start();
        }

        void OpenVPN_Exited(object sender, EventArgs e)
        {
           /* TSopenvpn.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate
            {
                TSopenvpn.IsChecked = false;
            }));*/
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            (MainTab.Items[0] as TabItem).IsEnabled = false;
            (MainTab.Items[1] as TabItem).IsEnabled = true;
            (MainTab.Items[2] as TabItem).IsEnabled = true;
            
            MainTab.SelectedIndex = 1;
            Username = txtBoxUsername.Text;
            Password = txtBoxPassword.Password;

        
        }

        ConnectionForwarder forwarder = null;
        ConnectionManager conman;
        private void ToggleSwitch_Checked(object sender, RoutedEventArgs e)
        {
            if (forwarder == null)
            {
                forwarder = new ConnectionForwarder("10.8.0.1", 3128, 3128);
                forwarder.Start();
            }
            if (Server == null ||  Network < 0 || (int)Network > 6)
            {
                //TSnetflux.IsChecked = false;
                return;
            }
            conman = new ConnectionManager(3130, Network);
            conman.AssignServer(Server);
            conman.Start();


            
        }

        private void ToggleSwitch_Checked_1(object sender, RoutedEventArgs e)
        { 
            if (!IsOpenVPNRunning)
                StartOpenVPN();
        }

        private void MainTab_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (MainTab.SelectedIndex == 1)
            {

                listViewServer.Items.Refresh();
                for (int i = 0; i < listViewServer.Items.Count; i++)
                {
                    Server s = listViewServer.Items[i] as Server;
                    if (s == null)
                        continue;
                    Thread update = new Thread(() =>
                    {
                        s.UpdateStatus();
                        listViewServer.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate
                        {
                            listViewServer.Items.Refresh();
                        }));
                    }) { IsBackground = true };
                    update.Start();
                }

                new Thread(() =>
                {
                    Thread.Sleep(5000);
                    listViewServer.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate
                    {
                        listViewServer.Items.Refresh();
                    }));
                    Thread.Sleep(10000);
                    listViewServer.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate
                    {
                        listViewServer.Items.Refresh();
                    }));
                }
            ).Start();
            }
        }

        Timer updateStatusTimer;
        private void UpdateStatus()
        {
            updateStatusTimer = new Timer(new TimerCallback((object o) =>
            {
                //int valid_replies = 0;
                for (int i = 0; i < 120; i++)
                {
                    Ping p = new Ping();
                    PingReply reply = null;
                    try
                    {
                        reply = p.Send("10.8.0.1");
                        if (reply.RoundtripTime > 0 && reply.RoundtripTime < 2000)
                        {
                            progressBarStatus.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate
                            {
                                progressBarStatus.Value++;

                                if (progressBarStatus.Value > 25)
                                {

                                   

                                }
                            }));
                        }
                        else
                        {
                            progressBarStatus.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate
                            {
                                progressBarStatus.Value--;
                            }));
                        }
                    }
                    catch
                    {
                    }

                }
            

            }));
            updateStatusTimer.Change(10000 * 2, 10000 * 1);
            
        }

        private void listView1_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ServerId = listViewServer.SelectedIndex;
        }

        private void listBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            NetworkId = int.Parse((listBoxNetwork.SelectedItem as Image).Tag.ToString());
            try
            {
                conman.SetNetwork(Network);
            }
            catch
            {
            }
        }

        private void TSopenvpn_Unchecked(object sender, RoutedEventArgs e)
        {
            StreamWriter writer;
            try
            {
                writer = OpenVPN.StandardInput;
            }
            catch
            {
                return;
            }
            writer.Write(ConsoleKey.F4);
            writer.Flush();
            writer.Write(Key.F4);
            writer.Flush();

            EventWaitHandle resetEvent;
            try
            {
                resetEvent = EventWaitHandle.OpenExisting(eventname);
            }
            catch
            {
                return;
            }

            resetEvent.Set();
            resetEvent.Close();
            resetEvent.Dispose();


           // writer.Write(Key.C & Key.LeftCtrl);
           // writer.Flush();
        }

        private void TSnetflux_Unchecked(object sender, RoutedEventArgs e)
        {
            try
            {
                conman.Stop();
            }
            catch
            {
            }
        }

        private void Image_ImageFailed(object sender, ExceptionRoutedEventArgs e)
        {

        }

        private void MiDarkOrange(object sender, RoutedEventArgs e)
        {
            ThemeManager.ChangeTheme(this, ThemeManager.DefaultAccents.First(a => a.Name == "Orange"), Theme.Dark);
        }

        private void MiLightOrange(object sender, RoutedEventArgs e)
        {
            ThemeManager.ChangeTheme(this, ThemeManager.DefaultAccents.First(a => a.Name == "Orange"), Theme.Light);
        }

        private void MiLightRed(object sender, RoutedEventArgs e)
        {
            ThemeManager.ChangeTheme(this, ThemeManager.DefaultAccents.First(a => a.Name == "Red"), Theme.Light);
        }

        private void MiDarkRed(object sender, RoutedEventArgs e)
        {
            ThemeManager.ChangeTheme(this, ThemeManager.DefaultAccents.First(a => a.Name == "Red"), Theme.Dark);
        }

        private void MiLightGreen(object sender, RoutedEventArgs e)
        {
            ThemeManager.ChangeTheme(this, ThemeManager.DefaultAccents.First(a => a.Name == "Green"), Theme.Light);
        }

        private void MiDarkGreen(object sender, RoutedEventArgs e)
        {
            ThemeManager.ChangeTheme(this, ThemeManager.DefaultAccents.First(a => a.Name == "Green"), Theme.Dark);
        }

        private void MiLightBlue(object sender, RoutedEventArgs e)
        {
            ThemeManager.ChangeTheme(this, ThemeManager.DefaultAccents.First(a => a.Name == "Blue"), Theme.Light);
        }

        private void MiDarkBlue(object sender, RoutedEventArgs e)
        {
            ThemeManager.ChangeTheme(this, ThemeManager.DefaultAccents.First(a => a.Name == "Blue"), Theme.Dark);
        }

        private void MiLightPurple(object sender, RoutedEventArgs e)
        {
            ThemeManager.ChangeTheme(this, ThemeManager.DefaultAccents.First(a => a.Name == "Purple"), Theme.Light);
        }

        private void MiDarkPurple(object sender, RoutedEventArgs e)
        {
            ThemeManager.ChangeTheme(this, ThemeManager.DefaultAccents.First(a => a.Name == "Purple"), Theme.Dark);
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            (sender as Button).ContextMenu.Visibility = System.Windows.Visibility.Visible;
            (sender as Button).ContextMenu.IsOpen = true;
        }

        private void MetroWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            try
            {
                EventWaitHandle resetEvent;
                try
                {
                    resetEvent = EventWaitHandle.OpenExisting(eventname);
                }
                catch 
                {
                    return;
                }

                resetEvent.Set();
                resetEvent.Close();
                resetEvent.Dispose();

                OpenVPN.Kill();
            }
            catch
            {
            }
         
            try
            {
                forwarder.Stop();
            }
            catch
            {
            }
  
        }

        private void versionButton_Click(object sender, RoutedEventArgs e)
        {
        
        }

        
        private void MenuItem_Click_1(object sender, RoutedEventArgs e)
        {
            updater = new AppLimit.NetSparkle.Sparkle("http://dl.dropbox.com/u/32551105/NetFluxUpdater/versioninfo.xml");

         //   updater.EnableSilentMode = true;
            updater.HideReleaseNotes = true;

            updater.StartLoop(true);

            (sender as MenuItem).IsEnabled = false;
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            if (forwarder == null)
            {
                forwarder = new ConnectionForwarder("10.8.0.1", 3128, 3128);
                forwarder.Start();
            }
            if (Server == null || Network < 0 || (int)Network > 6)
            {
                //TSnetflux.IsChecked = false;
                return;
            }
            conman = new ConnectionManager(3130, Network);
            conman.AssignServer(Server);
            conman.Start();

            if (!IsOpenVPNRunning)
                StartOpenVPN();
        }   
    }
}
